#!/usr/bin/python3
# -*- coding: utf8 -*-
# Date   : 2021/09/01
# Author : Kwan
# Email  : allenxian@live.com
# Blog   : https://my.oschina.net/u/4173440

import json, requests, win32api, win32con, winreg
from os import environ
from threading import Thread
from queue import Queue
from time import sleep
from .client import Client


class Collector:
    MessageQ = Queue()
    # 每300秒自动扫描一次硬件和系统，然后POST到服务器
    def __init__(self, url) -> None:
        # 提交接口
        self.ServerURL = url
        self.Snapshot = ""
        self.SoftwareCount = 0
        self.SoftwareSnapshot = []
        self.Client = Client()

    def collect_task(self):
        # 采集任务
        try:
            self.Client.device_scan()
            ret = self.Client.__dict__.copy()
            if ret != self.Snapshot:
                self.Snapshot = ret
                data = {"ClientInfo":ret}
            else:
                data = {"ClientSerial":ret["SerialNumber"]}
            ret = self.current_softwares()
            if ret:
                data["SoftwareList"] = ret
            js_data = json.dumps(data,ensure_ascii=False)
            # 保存为本地JSON文件
            if "ClientInfo" in data:
                data_file = f"{environ['USERPROFILE']}\\.client.json"
                with open(data_file, mode="w", encoding="utf8") as f:
                    f.write(js_data)
            # POST
            with requests.post(url=self.ServerURL, json=js_data, timeout=2) as r:
                if r.status_code == 200:
                    ret = r.json()
                    if isinstance(ret, dict):
                        msg = ret.get('Message')
                        if msg:
                            self.MessageQ.put(msg)
        except:
            pass
    
    def show_solve_info(self):
        # 显示结果
        while 1:
            if not self.MessageQ.empty():
                msg = self.MessageQ.get()
                win32api.MessageBox(0, msg, "事件处理结果", win32con.MB_OK)
            sleep(1)

    def current_softwares(self):
        # HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
        # HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
        # DisplayName：软件名
        # DisplayVersion：版本
        # InstallLocation：安装位置
        # InstallDate：安装日期
        # Publisher：发布者
        keys = (
            r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
            r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        )
        software_list = []
        if self.Client.Arch == "32位":
            keys = [keys[0]]
        # winreg.CloseKey(winreg.HKEY_LOCAL_MACHINE)
        access_registry = winreg.ConnectRegistry(None,winreg.HKEY_LOCAL_MACHINE)
        for k in keys:
            with winreg.OpenKey(access_registry, k) as access_key:
                key_count = 0
                while True:
                    try:
                        key_count += 1
                        x = winreg.EnumKey(access_key,key_count)
                        if ".KB" not in x:
                            fulle_path = k + rf"\{x}"
                            if fulle_path not in software_list:
                                software_list.append(fulle_path)
                    except:
                        break
        # 分析注册表软件
        ret = []
        reg_info = ("DisplayName","DisplayVersion","Publisher")
        for r in software_list:
            try:
                with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r, 0, winreg.KEY_READ) as r_reg:
                    values = [winreg.QueryValueEx(r_reg, i)[0] for i in reg_info]
                if len(values) > 0 and None not in values:
                    # {'DisplayName': '钉钉', 'DisplayVersion': '6.0.22-Release.7190187', 'Publisher': 'Alibaba (China) Network Technology Co.,Ltd.'}
                    ret.append(dict(zip(reg_info, values)))
            except WindowsError:
                key_count -= 1
        if self.SoftwareCount != key_count or self.SoftwareSnapshot != ret:
            self.SoftwareCount = key_count
            self.SoftwareSnapshot = ret
            return ret

    def threads_init(self):
        # 服务初始化
        show_t = Thread(target=self.show_solve_info)
        for t in (show_t,):
            t.setDaemon(True)
            t.start()
 
    def service_start(self, interval_time):
        # 服务开始
        self.threads_init()
        while True:
            self.collect_task()
            sleep(interval_time)
            